#pragma once

#include<iostream>
#include<queue>
#include<thread>
#include<mutex>
#include<condition_variable>
namespace BlockQueueModule
{
    const int gcap = 10; //最大容量

    template<typename T>
    class BlockQueue
    {
    private:
        bool IsFull() {return _q.size() == _cap;}
        bool IsEmpty(){return _q.empty();}
    public:
        BlockQueue(int cap = gcap):_cap(cap), _cwait_num(0), _pwait_num(0)
        {
            // pthread_mutex_init(&_mutex, nullptr);
            // pthread_cond_init(&_productor_cond, nullptr);
            // pthread_cond_init(&_consumer_cond, nullptr);
        }
        void Equeue(const T& in) //生产
        {
            std::unique_lock<std::mutex> lock(_mutex);
            while (IsFull())
            {
                //容量达到上限
                //pthread_cond_wait(&_productor_cond);
                _pwait_num++;
                _productor_cond.wait(lock, [this]{ return !IsFull(); });
                _pwait_num--;
            }
            //容量未达到上限
            _q.push(in);

            if(_cwait_num){
                _consumer_cond.notify_one();
            }
            //解锁
            lock.unlock();
        }
        void Pop(T* out)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            while (IsEmpty())
            {
                _cwait_num++;
                _productor_cond.wait(lock, [this]{ return !IsEmpty(); });
                _cwait_num--;
            }
            *out = _q.front();
            _q.pop();

            //肯定还有空间
            if(_pwait_num)
            {
                _productor_cond.notify_one();
            }
            lock.unlock();
        }
        ~BlockQueue()
        {
            // pthread_mutex_destroy(&mutex);
            // pthread_cond_destroy(&_productor_cond);
            // pthread_cond_destroy(&_consumer_cond);
        }
    private:
        std::queue<T> _q;
        int _cap;
        // pthread_mutex_t _mutex;
        // pthread_cond_t _productor_cond;
        // pthread_cond_t _consumer_cond;
        std::mutex _mutex;
        std::condition_variable _productor_cond;
        std::condition_variable _consumer_cond;

        int _pwait_num;
        int _cwait_num;
    };
};
